package com.rms.hkpc.audio;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import java.io.File;
import java.io.IOException;

public class AudioRecordManager implements Handler.Callback {

    private int RECORD_INTERVAL;
    private String SAVE_PATH;
    private AudioState mCurAudioState;
    private Context context;
    private Handler mHandler;
    private AudioManager mAudioManager;
    private MediaRecorder mMediaRecorder;
    private Uri mAudioPath;
    private long smStartRecTime;
    private AudioManager.OnAudioFocusChangeListener mAfChangeListener;
    private AudioState idleState;
    private AudioState recordState;
    private AudioState sendingState;
    private AudioState cancelState;
    private AudioState timerState;
    private static volatile AudioRecordManager instance;

    public static AudioRecordManager getInstance(Context context) {
        if (instance == null) {
            synchronized (AudioRecordManager.class) {
                if (instance == null) {
                    instance = new AudioRecordManager(context);
                }
            }
        }
        return instance;
    }

    public AudioRecordManager(Context context) {
        this.context = context;
        mHandler = new Handler(this);
        RECORD_INTERVAL = 60;
        idleState = new IdleState();
        recordState = new RecordState();
        sendingState = new SendingState();
        cancelState = new CancelState();
        timerState = new TimerState();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            try {
                TelephonyManager e = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                // 创建一个通话状态监听器
                e.listen(new PhoneStateListener() {
                    @Override
                    public void onCallStateChanged(int state, String phoneNumber) {
                        switch (state) {
                            case TelephonyManager.CALL_STATE_RINGING:
                                sendEmptyMessage(6);
                                break;
                            case TelephonyManager.CALL_STATE_IDLE:
                            case TelephonyManager.CALL_STATE_OFFHOOK:
                            default:
                                super.onCallStateChanged(state, phoneNumber);
                        }

                    }
                }, 32);
            } catch (SecurityException e) {
                e.printStackTrace();
            }
        }
        setCurIsIdle();
    }

    private IAudioRecordListener mAudioRecordListener;

    public void setAudioRecordListener(IAudioRecordListener audioRecordListener) {
        mAudioRecordListener = audioRecordListener;
    }

    /**
     * 设置音频存储位置
     *
     * @param path
     */
    public void setAudioSavePath(String path) {
        if (TextUtils.isEmpty(path)) {
            SAVE_PATH = context.getCacheDir().getAbsolutePath();
        } else {
            SAVE_PATH = path;
        }
    }

    public void startRecord() {
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        if (mAfChangeListener != null) {
            muteAudioFucus(mAudioManager, false);
        }

        mAfChangeListener = new AudioManager.OnAudioFocusChangeListener() {
            @Override
            public void onAudioFocusChange(int focusChange) {
                if (focusChange == -1) {
                    muteAudioFucus(mAudioManager, false);
                    sendEmptyMessage(6);
                }
            }
        };
        sendEmptyMessage(1);
        if (mAudioRecordListener != null) {
            mAudioRecordListener.onStartRecord();
        }
    }

    public void willCancelRecord() {
        this.sendEmptyMessage(3);
    }

    public void continueRecord() {
        this.sendEmptyMessage(4);
    }

    public void stopRecord() {
        this.sendEmptyMessage(5);
    }

    /**
     * 设置音频音量
     *
     * @param maxVoiceDuration
     */
    public void setMaxVoiceDuration(int maxVoiceDuration) {
        RECORD_INTERVAL = maxVoiceDuration;
    }

    private void setCurIsIdle() {
        this.mCurAudioState = this.idleState;
        idleState.enter();
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        AudioStateMessage m;
        switch (msg.what) {
            case 2:
                this.sendEmptyMessage(2);
                break;
            case 7:
                m = AudioStateMessage.obtain();
                m.what = msg.what;
                m.obj = msg.obj;
                this.sendMessage(m);
                break;
            case 8:
                m = AudioStateMessage.obtain();
                m.what = 7;
                m.obj = msg.obj;
                this.sendMessage(m);
        }
        return false;
    }

    private class IdleState extends AudioState {

        public IdleState() {
        }

        @Override
        void enter() {
            super.enter();
            if (AudioRecordManager.this.mHandler != null) {
                AudioRecordManager.this.mHandler.removeMessages(7);
                AudioRecordManager.this.mHandler.removeMessages(8);
                AudioRecordManager.this.mHandler.removeMessages(2);
            }
        }

        @Override
        void audioHandleMessage(AudioStateMessage msg) {
            if (msg.what == 1) {
                initView();
                setRecordingView();
                startRec();
                // 获取设备开机到现在的时间
                smStartRecTime = SystemClock.elapsedRealtime();
                mCurAudioState = recordState;
                sendEmptyMessage(2);
            }
        }
    }

    /**
     * 初始化提示视图
     */
    private void initView() {
        if (mAudioRecordListener != null) {
            mAudioRecordListener.initTipView();
        }
    }

    /**
     * 设置超时视图
     *
     * @param counter
     */
    private void setTimeoutView(int counter) {
        if (mAudioRecordListener != null) {
            mAudioRecordListener.setTimeoutTipView(counter);
        }
    }

    /**
     * 设置正在录制提示视图
     */
    private void setRecordingView() {
        if (mAudioRecordListener != null) {
            mAudioRecordListener.setRecordingTipView();
        }
    }

    /**
     * 设置取消提示视图
     */
    private void setCancelView() {
        if (mAudioRecordListener != null) {
            mAudioRecordListener.setCancelTipView();
        }
    }

    /**
     * 销毁提示视图
     */
    private void destroyView() {
        mHandler.removeMessages(7);
        mHandler.removeMessages(8);
        mHandler.removeMessages(2);
        if (mAudioRecordListener != null) {
            mAudioRecordListener.destroyTipView();
        }
    }

    /**
     * 初始化MediaRecorder，设置参数，开始录音
     */
    @SuppressLint("WrongConstant")
    private void startRec() {
        try {
            muteAudioFucus(mAudioManager, true);
            mAudioManager.setMode(0);
            mMediaRecorder = new MediaRecorder();
            try {
                // 设置录制的音频采样率
                mMediaRecorder.setAudioSamplingRate(8000);
                // 设置录制的音频编码比特率
                mMediaRecorder.setAudioEncodingBitRate(7950);
            } catch (Resources.NotFoundException var3) {
                var3.printStackTrace();
            }
            // 设置录制的音频通道数
            mMediaRecorder.setAudioChannels(1);
            // 声音资源
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            // 输出格式
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            // 音频编码
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            mAudioPath = Uri.fromFile(new File(SAVE_PATH, System.currentTimeMillis() + ".m4a"));
            // 设置输出文件的路径
            mMediaRecorder.setOutputFile(mAudioPath.getPath());
            mMediaRecorder.prepare();
            mMediaRecorder.start();
            Message message = Message.obtain();
            message.what = 7;
            message.obj = 10;
            mHandler.sendMessageDelayed(message, RECORD_INTERVAL * 1000 - 10000);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取或销毁焦点
     *
     * @param audioManager
     * @param bMute
     */
    private void muteAudioFucus(AudioManager audioManager, boolean bMute) {
        if (bMute) {
            audioManager.requestAudioFocus(mAfChangeListener, 3, 2);
        } else {
            audioManager.abandonAudioFocus(mAfChangeListener);
            this.mAfChangeListener = null;
        }
    }

    private void sendEmptyMessage(int event) {
        AudioStateMessage message = AudioStateMessage.obtain();
        message.what = event;
        mCurAudioState.audioHandleMessage(message);
    }

    private class RecordState extends AudioState {
        public RecordState() {
        }

        @Override
        void audioHandleMessage(AudioStateMessage msg) {
            switch (msg.what) {
                case 2:
                    audioDBChange();
                    mHandler.sendEmptyMessageDelayed(2, 50L);
                    break;
                case 3:
                    setCancelView();
                    mCurAudioState = cancelState;
                    break;
                case 5:
                    final boolean checked = checkAudioTimeLength();
                    boolean activityFinished = false;
                    if (msg.obj != null) {
                        activityFinished = (boolean) msg.obj;
                    }
                    // 录制时间过短，取消录音，并提示时间过短
                    if (checked && !activityFinished) {
                        if (mAudioRecordListener != null) {
                            mAudioRecordListener.setAudioShortTipView();
                        }
                        mHandler.removeMessages(2);
                    }
                    if (!activityFinished && mHandler != null) {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                AudioStateMessage message = AudioStateMessage.obtain();
                                message.what = 9;
                                message.obj = !checked;
                                sendMessage(message);
                            }
                        }, 500L);
                        mCurAudioState = sendingState;
                    } else {
                        stopRec();
                        if (!checked && activityFinished) {
                            finishRecord();
                        }
                        destroyView();
                        mCurAudioState = idleState;
                    }
                    break;
                case 6:
                    stopRec();
                    destroyView();
                    deleteAudioFile();
                    setCurIsIdle();
                    break;
                case 7:
                    int counter = (int) msg.obj;
                    setTimeoutView(counter);
                    mCurAudioState = timerState;
                    if (counter > 0) {
                        Message message = Message.obtain();
                        message.what = 8;
                        message.obj = counter - 1;
                        mHandler.sendMessageDelayed(message, 1000L);
                    } else {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                stopRec();
                                finishRecord();
                                destroyView();
                            }
                        }, 500L);
                        mCurAudioState = idleState;
                    }
                    break;
            }
        }
    }

    /**
     * 改变录音分贝
     */
    private void audioDBChange() {
        if (mMediaRecorder != null) {
            // 获取前一次录音中出现的最大振幅
            int db = mMediaRecorder.getMaxAmplitude() / 600;
            if (mAudioRecordListener != null) {
                mAudioRecordListener.onAudioDBChanged(db);
            }
        }
    }

    /**
     * 判断录音时间是否过短
     *
     * @return
     */
    private boolean checkAudioTimeLength() {
        // 获取设备开机到现在的时间与设备开机到开始录制时间差
        long delta = SystemClock.elapsedRealtime() - smStartRecTime;
        return delta < 1000L;
    }

    private void sendMessage(AudioStateMessage message) {
        mCurAudioState.audioHandleMessage(message);
    }

    /**
     * 关闭录音
     */
    private void stopRec() {
        try {
            muteAudioFucus(mAudioManager, false);
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 结束录音
     */
    private void finishRecord() {
        if (mAudioRecordListener != null) {
            int duration = (int) ((SystemClock.elapsedRealtime() - smStartRecTime) / 1000);
            mAudioRecordListener.onFinish(mAudioPath, duration);
        }
    }

    /**
     * 删除音频文件
     */
    private void deleteAudioFile() {
        if (mAudioPath != null) {
            File file = new File(mAudioPath.getPath());
            if (file.exists()) {
                file.delete();
            }
        }
    }

    private class SendingState extends AudioState {

        public SendingState() {
        }

        @Override
        void audioHandleMessage(AudioStateMessage msg) {
            if (msg.what == 9) {
                stopRec();
                if ((Boolean) msg.obj) {
                    finishRecord();
                }
                destroyView();
                mCurAudioState = idleState;
            }
        }
    }

    private class CancelState extends AudioState {

        public CancelState() {
        }

        @Override
        void audioHandleMessage(AudioStateMessage msg) {
            switch (msg.what) {
                case 4:
                    setRecordingView();
                    mCurAudioState = recordState;
                    sendEmptyMessage(2);
                    break;
                case 5:
                case 6:
                    stopRec();
                    destroyView();
                    deleteAudioFile();
                    setCurIsIdle();
                    break;
                case 7:
                    int counter = (int) msg.obj;
                    if (counter > 0) {
                        Message message = Message.obtain();
                        message.what = 8;
                        message.obj = counter - 1;
                        mHandler.sendMessageDelayed(message, 1000L);
                    } else {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                stopRec();
                                finishRecord();
                                destroyView();
                            }
                        }, 500L);
                        setCurIsIdle();
                    }
                    break;
            }
        }
    }

    private class TimerState extends AudioState {

        public TimerState() {
        }

        @Override
        void audioHandleMessage(AudioStateMessage msg) {
            switch (msg.what) {
                case 3:
                    setCancelView();
                    mCurAudioState = cancelState;
                    break;
                case 5:
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            stopRec();
                            finishRecord();
                            destroyView();
                        }
                    }, 500L);
                    setCurIsIdle();
                    break;
                case 6:
                    stopRec();
                    destroyView();
                    deleteAudioFile();
                    setCurIsIdle();
                    break;
                case 7:
                    int counter = (int) msg.obj;
                    if (counter > 0) {
                        Message message = Message.obtain();
                        message.what = 8;
                        message.obj = counter - 1;
                        mHandler.sendMessageDelayed(message, 1000L);
                        setTimeoutView(counter);
                    } else {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                stopRec();
                                finishRecord();
                                destroyView();
                            }
                        }, 500L);
                        mCurAudioState = idleState;
                    }
                    break;
            }
        }
    }
}
